MAX_ROOMNO EQU 331
PUTPLAYER:
        MOV DI,PL_AD
 PUTPL1:
        MOV CH,ROOMCOLOR
        CMP CH,-1
        JNE >L1
        CMP COLOR?,0
        JNE >Z1
        MOV CH,CBCOLORBW[0]
        TEST LCNT,2
        IF NZ MOV CH,CBCOLORBW[2]
        JMP >L1
     Z1:
        LDFLASHCOLOR CH
        SHL CH,1
        SHL CH,1
        SHL CH,1
        SHL CH,1
     L1:
        MOV AL,020
        MOV ES,BX,VIDSEG_MAIN
        CMP DI,160*24
        JAE RET
        MOV AH,[ES:DI+1]
        AND AH,0F
        OR AH,CH
        STOSW
        MOV AH,[ES:DI+1]
        AND AH,0F
        OR AH,CH
        STOSW
        RET
PUTROOM:
        MOV LC_FLAG,0
        MOV W[OFFSET COPEN_CNT],0
        MOV SHIFTCTRLALTA,0
        MOV SI,ROOMDAT
        MOV AX,ROOM
        CMP AX,-1
        IF E JMP TITLEPG
        PUSH BX
        MOV BX,60
        PUSH DX
        MUL BX
        POP DX
        ADD SI,AX
        MOV BX,RMCOLORS
        ADD BX,ROOM
        MOV AL,[BX]
        MOV ROOMCOLOR,AL
        CMP AL,-1
        JNE >P0
        PUSH BX
        LDFLASHCOLOR AL
        POP BX
        JMP >Q0
     P0:
        CMP ROOMCOLOR,CAT
        JE >Q0
        CMP COLOR?,0
        JNE >Q0
        MOV ROOMCOLOR,BWOffWhite*16
        CMP ROOM,11
        IF E MOV ROOMCOLOR,BWDGray*16
     Q0:
        MOV TEMPB,AL
        MOV BX,VIDSEG
        CMP AL,CAT
        JNE >H0
        ADD BX,0100*CAT_TXTPG       ; 2nd page
        MOV DI,01000*ALLGRAY_TXTPG  ; address for page 3
        MOV ES,AX,VIDSEG
        MOV CX,80*24
        MOV AX,CAT BY ' '
        REP STOSW      ; make page 3 100% gray
        MOV CX,80
        PUSH SI
        PUSH DS
        MOV SI,0F00
        MOV DS,ES
        REP MOVSW
        POP DS
        POP SI
     H0:
        MOV ES,BX
        MOV DI,0
        MOV CX,12
        CMP ROOM,331
        LAHF
        IF AE SHL CX,1
        MOV BH,ROOMCOLOR
        MOV BL,' '
     P1:
        PUSH CX
        MOV CX,5
     P2:
        LODSB
        PUSH CX
        MOV CX,8
     P3:
        PUSH BX
        SHL AL,1
        JC >P5
     P4:
        MOV BH,CAT
        CMP BH,ROOMCOLOR
        JNE >P5
        MOV BH,0C0  ; orange
        PUSHF
        CMP COLOR?,0
        IF E MOV BH,BWOffWhite*16
        POPF
     P5:
        SAHF  ;CMP ROOM,331
        JAE >H1
        MOV [ES:DI+160],BX
        MOV [ES:DI+162],BX
     H1:MOV [ES:DI],BX
        MOV [ES:DI+2],BX
        ADD DI,4
        POP BX
        LOOP P3
        POP CX
        LOOP P2
        POP CX
        SAHF  ;CMP ROOM,331
        IF B ADD DI,160
        LOOP P1
        CMP ROOMCOLOR,CAT
        JE >H2
        MOV AX,5 by MAIN_TXTPG
        INT 010
     H2:
        MOV AL,0FF
        CMP SHOWDIF_CNT,0
        IF NE CALL PRINTDIFS
        CMP LASTGOOD_RM,-1
        JNE >L0
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,160*24+74
        MOV CX,8
        MOV AX,0720
        REP STOSW
     L0:
;check for lines/gates
        CMP ROOM,5
        JE >L1
        CMP ROOM,21
        JNE >L2
     L1:OR LC_FLAG,8
     L2:MOV LINE_OBJ_PTR,OBJECT
        MOV LINE_COLOR_PTR,OFFSET OBJ_COLOR
        CMP COLOR?,0
        IF E MOV LINE_COLOR_PTR,OFFSET OBJ_COLORBW
        MOV ES,CS
        MOV DI,LEFTLINE
        MOV CX,NUM_LEFTLINE_ROOMS  ;9
        MOV AX,ROOM
        REPNE SCASW
        JNE >P6
        OR LC_FLAG,080
        JMP >P7
     P6:
        MOV DI,RIGHTLINE
        MOV CX,NUM_RIGHTLINE_ROOMS   ;8
        REPNE SCASW
        JNE >P9
        OR LC_FLAG,040
     P7:
        JMP >P11
     P9:
        MOV DI,CASTLE_TABLE
        MOV CX,5
        REPNE SCASW
        JNE >P11
        OR LC_FLAG,020
        MOV BX,4
        SUB BX,CX
        MOV ES,AX,VIDSEG_MAIN
        MOV SI,(160*14)+76
        MOV CX,4
        CMP GATE[BX],0   ;open?
        JE >P10
        MOV CX,1
        OR LC_FLAG,010
    P10:
        MOV B[ES:SI],0CC
        MOV B[ES:SI+2],0CE
        MOV B[ES:SI+4],0CE
        MOV B[ES:SI+6],0B9
        ADD SI,160
        LOOP P10
    P11:
        POP BX
        CMP ROOMCOLOR,CAT
        JNE RET
        CALL GRAYOUT_SCREEN
        JMP PUTCAT
GRAYOUT_SCREEN:
        MOV DI,0
        MOV ES,AX,VIDSEG
        MOV AX,CAT BY 020
        MOV CX,80*24
        REP STOSW     ; gray-out screen
        RET
PUTCAT:
#IF REGISTERED
        INC PUTCAT_DRAWN
        CMP ROOMCOLOR,CAT
        JNE RET
        PUSH BX
        PUSH DX
        MOV AX,PL_AD
        DIV v_160
        SUB AH,14
        MOV TEMPB,AH           ; player col - 14
        MOV TEMPB[1],0         ; AH is positive (or is it?)
        CMP AH,200   ;negative?
        IF A DEC TEMPB[1]      ; AH is negative, thus col < 14
        ADD AH,14+16
        MOV TEMPB[2],AH        ; col + 16
        MOV TEMPB[3],0         ;
        MUL v_160
        SUB AX,3*160
        MOV TEMP[4],AX
        ADD AX,3*160+3*160
        MOV TEMP[6],AX
        ADD AX,320
        MOV DX,AX
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,TEMP[4]
        SUB DI,320
        IF S MOV DI,0
        MOV AL,020
    P12:
        MOV BX,TEMP
        SUB BX,8
        IF S MOV BX,0
        MOV CX,TEMP[2]
        ADD CX,10
        SUB CX,BX
        SHR CX,1
    P13:
        MOV AH,CAT
        CMP DI,TEMP[4]
        JL >P14
        CMP DI,TEMP[6]
        JG >P14
        CMP BX,TEMP
        JL >P14
        CMP BX,TEMP[2]
        JG >P14
        MOV AH,[ES:DI+BX+01000*CAT_TXTPG+1]
    P14:
        MOV [ES:DI+BX],AX
        ADD BX,2
        CMP BX,160
        JAE >P15
        LOOP P13
    P15:
        ADD DI,160
        CMP DI,160*24
        JAE >P16
        CMP DI,DX
        JBE P12
    P16:
        POP DX
        POP BX
;        CALL CHECKBLINK
;        MOV AX,5 BY MAIN_TXTPG
;        IF NZ MOV AL,ALLGRAY_TXTPG
;        INT 010
#ENDIF
        RET
PUTLINE:  ;Entry: SI=top addr
        PUSH DI
        MOV DL,0  ; bat/nothing
        PUSH SI
        CMP BLINK_CTR,3
        IF AE JMP LONG >L5
        TEST LC_FLAG,040  ; not Right-side line?
        JZ >L0
        MOV AX,ROOM
        CMP AX,[OBJECT+OSZ*n_BRIDGE] ; bridge takes precedence
        JNE >R1
        MOV DL,[OBJ_COLOR+n_BRIDGE]
        CMP COLOR?,0
        IF E MOV DL,[OBJ_COLORBW+n_BRIDGE]
        JMP >K1
     R1:
        CMP BLINK_CTR,2
        JB >K1
     L0:
        MOV SI,DRAGON+DRSZ*3
        MOV DI,(OFFSET OBJ_COLOR)+20
        CMP COLOR?,0
        IF E MOV DI,(OFFSET OBJ_COLORBW)+20
        MOV AX,ROOM
        MOV CX,4
     L1:
        DEC DI
        CMP AX,[SI]
        IF E MOV DL,[DI]
        SUB SI,DRSZ
        LOOP L1
        MOV SI,OBJECT+OSZ*15
        MOV CX,10
     L2:
        DEC DI
        CMP AX,[SI]
        IF E MOV DL,[DI]
        SUB SI,OSZ
        LOOP L2
     K1:
        POP SI
        CMP DL,-1
        JNE >L3
        PUSH BX
        LDFLASHCOLOR DL
        POP BX
     L3:
        MOV ES,AX,VIDSEG_MAIN
        MOV CX,24
        MOV AL,0DB
     L4:
        MOV AH,[ES:SI+1]
        CALL NEW_CHR_COLOR
        MOV [ES:SI],AX
        ADD SI,0A0
        LOOP L4
        POP DI
        RET
     L5:
        MOV AX,ROOM
        MOV SI,LINE_OBJ_PTR
        MOV DI,LINE_COLOR_PTR
        MOV CX,15
     L6:
        CMP SI,DRAGON
        IF AE ADD SI,2
        ADD SI,OSZ
        INC DI
        CMP AX,[SI]
        JE >L8
        CMP SI,BAT
        JNA >L7
        MOV SI,OBJECT-OSZ
        MOV DI,(OFFSET OBJ_COLOR)-1
        CMP COLOR?,0
        IF E MOV DI,(OFFSET OBJ_COLORBW)-1
     L7:
        LOOP L6
     L8:
        MOV DL,[DI]
        MOV LINE_OBJ_PTR,SI
        MOV LINE_COLOR_PTR,DI
        JMP K1
PUTGATE:
        TEST LC_FLAG,020
        JZ RET
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,(160*14)+76
        MOV SI,GATE_STRING
        ADD SI,VGA
        MOV DL,COPEN_CNT
        OR DL,CCLOSE_CNT
        IF S XOR DL,DL
        MOV CX,4
        CMP COPEN_CNT,0
        JE >L1
        MOV CL,COPEN_CNT
        ADD CL,3
        SHR CL,1
        JMP SHORT PG1
     L1:
        CMP CCLOSE_CNT,0
        JE >L2
        MOV CL,9
        SUB CL,CCLOSE_CNT
        SHR CL,1
        JMP SHORT PG1
     L2:
        TEST LC_FLAG,010
        IF NZ MOV CX,1
    PG1:
        PUSH SI
        CMP CL,1
        JNE >L3
        TEST DL,1
        IF NZ ADD SI,3
     L3:
        MOV AX,[SI]
        MOV B[ES:DI],AL
        MOV B[ES:DI+2],AH
        MOV B[ES:DI+4],AH
        MOV AL,[SI+2]
        MOV B[ES:DI+6],AL
        POP SI
        PUSH CX
        MOV CX,4
    PG2:
        AND B[ES:DI+1],0F0
        ADD DI,2
        LOOP PG2
        POP CX
        ADD DI,152
        LOOP PG1
        RET
ERAGATE:
        TEST LC_FLAG,020
        JZ RET
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,(14*160)+76
        MOV CX,4
        MOV AL,020
     L1:
        MOV [ES:DI],AL
        MOV [ES:DI+2],AL
        MOV [ES:DI+4],AL
        MOV [ES:DI+6],AL
        ADD DI,160
        LOOP L1
        RET
AD_INT9 DD
ORIGINAL_INT9 DW 0,0
INKEY   DB 0
COMBARROW DB 0  ;bits (1=down): Home|PgUp|End|PgDn|Left|Right|Up|Down
KP5     DB 0
KEYINT:
        CLI
        PUSH AX
        IN AL,060
        MOV AH,0
        CMP AL,sc_Keypad5
        IF E NOT AH
        MOV CS:KP5,AH
        CMP AL,sc_Home
        JB >K0
        CMP AL,sc_PgDn
        JA >K1
        MOV CS:INKEY,AL
        MOV AH,CS:COMBARROW
        CMP AL,sc_LeftArrow
        IF E OR AH,8
        CMP AL,sc_RightArrow
        IF E OR AH,4
        CMP AL,sc_UpArrow
        IF E OR AH,2
        CMP AL,sc_DownArrow
        IF E OR AH,1
        CMP AL,sc_Home
        IF E OR AH,080
        CMP AL,sc_PgUp
        IF E OR AH,040
        CMP AL,sc_End
        IF E OR AH,020
        CMP AL,sc_PgDn
        IF E OR AH,010
        MOV CS:COMBARROW,AH
     K0:
        POP AX
        JMP D[CS:AD_INT9]
     K1:
        CMP AL,sc_Home+080
        JB K0
        CMP AL,sc_PgDn+080
        JA K0
        MOV AH,CS:COMBARROW
        CMP AL,sc_LeftArrow+080
        IF E AND AH,0F7
        CMP AL,sc_RightArrow+080
        IF E AND AH,0FB
        CMP AL,sc_UpArrow+080
        IF E AND AH,0FD
        CMP AL,sc_DownArrow+080
        IF E AND AH,0FE
        CMP AL,sc_Home+080
        IF E AND AH,07F
        CMP AL,sc_PgUp+080
        IF E AND AH,0BF
        CMP AL,sc_End+080
        IF E AND AH,0DF
        CMP AL,sc_PgDn+080
        IF E AND AH,0EF
        MOV CS:COMBARROW,AH
        AND AL,07F
        CMP AL,CS:INKEY
        JNE K0  ;some other key being released, besides current direction
        MOV CS:INKEY,0
        POP AX
        JMP D[CS:AD_INT9]
ALinG_Q?:
        CMP AL,'G'
        JB RET
        CMP AL,'Q'
        JA RET
        CMP AL,AL
        RET
CONV_KEY:
        DMOV JOYVALS,START_JOYVALS
        CMP AL,'I'
        IF BE MOV VMOV,0
        CMP AL,'O'
        IF AE MOV VMOV,-1
        SUB AL,'G'
        TEST AL,3
        IF Z MOV HMOV,0
        SUB AL,2
        TEST AL,3
        IF Z MOV HMOV,-1
        RET
CONV_KEY_INT:            ; return AL = key
        MOV BL,CS:COMBARROW
        MOV AX,'L' BY 0
        SHR BL,1
        IF C ADD AH,4
        SHR BL,1
        IF C SUB AH,4
        SHR BL,1
        IF C INC AH
        SHR BL,1
        IF C DEC AH
        CMP BL,0
        JE >A9
        SHR BL,1
        IF C MOV AH,'Q'
        SHR BL,1
        IF C MOV AH,'O'
        SHR BL,1
        IF C MOV AH,'I'
        SHR BL,1
        IF C MOV AH,'G'
     A9:
        MOV AL,AH
        RET
AD_INT1B DD
ORIGINAL_INT1B DW 0,0
CTRL_BRK_PRESSED? DB 0
CTRL_BRK_INT:
        MOV CS:CTRL_BRK_PRESSED?,-1
        PUSH AX
;        IN AL,061     ;
;        OR AL,080     ;
;        OUT 061,AL    ;  for certain Compaq computers
;        AND AL,07F    ;
;        OUT 061,AL    ;
;;
;        IN AL,0A0     ;  for PCjr
;;
        MOV AL,020
        OUT 020,AL    ;  send standard EOI
        POP AX
        IRET
    CW9:
        CMP AL,AL
        RET
AD_INT24 DD
ORIGINAL_INT24 DW 0,0
ABORTRETRYFAIL_INT:
        STI
        MOV AL,3  ; code for "Fail"
        IRET
DIVERRM1 DB 'A divide error has occurred at $'
DIVERRM2 DB ', DX=$'
DIVERRM3 DB ', AX=$'
DIVERRM4 DB ', FLAGS=$'
DIVERRM5 DB ',',13,10,'divisor='
DIVISORHEX DB '  ??'
         DB ', version='
         DBVERSION
         DB '.',13,10,'Please inform the author of this bug.',13,10,'$'
AXDURINGDIV DW 0
DXDURINGDIV DW 0
AD_INT0 DD
ORIGINAL_INT0 DW 0,0
DIV_INT:
        MOV CS:AXDURINGDIV,AX
        MOV CS:DXDURINGDIV,DX
        PUSH AX
        MOV AL,020
        OUT 020,AL      ; send standard EOI
        POP AX
        STI
        CALL FINDDIVISOR
        MOV AX,3
        INT 010
        MOV AH,9
        LEA DX,DIVERRM1
        INT 021
        POP BX          ; get IP pushed by interrupt
        POP AX          ; get CS pushed by interrupt
        PUSH BX         ; put IP back temporarily
        MOV ES,AX       ; save segment for later
        CALL PRINTAXASHEX       ; print out CS
        MOV AH,6
        MOV DL,':'
        INT 021
        POP AX          ; get IP pushed by interrupt
        MOV DI,AX       ; save offset for later
        CALL PRINTAXASHEX       ; print out IP
        MOV AH,9
        LEA DX,DIVERRM2
        INT 021
        MOV AX,DXDURINGDIV
        CALL PRINTAXASHEX
        MOV AH,9
        LEA DX,DIVERRM3
        INT 021
        MOV AX,AXDURINGDIV
        CALL PRINTAXASHEX
        MOV AH,9
        LEA DX,DIVERRM4
        INT 021
        POP AX          ; get Flags pushed by interrupt
        CALL PRINTAXASHEX
        MOV AH,9
        LEA DX,DIVERRM5
        INT 021
        MOV CURSORROWONEXIT,3
        JMP EXIT_NOCLS
FINDDIVISOR:
        PUSH DI,ES
        PUSH BP
        MOV BP,SP
        LES DI,[BP+8]   ; ES:DI = location pushed when interrupt occurred
        POP BP
OPCODE_DIV_B    EQU 0F6
OPCODE_DIV_W    EQU 0F7
OPCODE_MOV_B    EQU 08A         ; MOV reg,ea
; First, let's find where the error occurred.
     E0:
        CMP B[ES:DI],OPCODE_DIV_B
        JE >E1
        CMP B[ES:DI],OPCODE_DIV_W
        JE >E1
; ES:DI points to something other than a DIV instruction, so it must be
; pointing to the NEXT instruction.  So, let's search backwards for a DIV.
        DEC DI
        JMP E0
     E1:
; Now, some self-modifying code (be afraid!).
        PUSH AX
        MOV AL,[ES:DI]  ; get instruction
        SUB AL,OPCODE_DIV_B-OPCODE_MOV_B     ; DIV B -> MOV B, DIV W -> MOV W
        EXTRN GETDIVISOR:B
        MOV GETDIVISOR,AL       ; store MOV instruction
        MOV AL,[ES:DI+1]  ; get EA
        MOV GETDIVISOR[1],AL    ; store EA
        PUSH AX
        AND AL,0F0
        CMP AL,070      ; is EA followed by 8-bit offset?
        POP AX
        JNE >E2         ; no
        MOV AL,[ES:DI+2]
        MOV GETDIVISOR[2],AL    ; store 8-bit offset
        JMP >E4
     E2:
        CMP AL,036      ; is EA followed by 16-bit absolute (no regs)?
        JE >E3          ; yes
        AND AL,0F0
        CMP AL,0B0      ; is EA followed by 16-bit offset?
        JNE >E4         ; no, so it's just a 2-byte instruction, no offsets
     E3:
        PUSH W[ES:DI+2]
        EXTRN GETDIVISOR_WOFS:W
        POP GETDIVISOR_WOFS     ; store 16-bit offset
     E4:
        POP AX
; Now check for a segment-override byte...
OPCODE_CS EQU 02E
OPCODE_DS EQU 03E
OPCODE_ES EQU 026
        CMP B[ES:DI-1],OPCODE_CS
        JE >E5
        CMP B[ES:DI-1],OPCODE_DS
        JE >E5
        CMP B[ES:DI-1],OPCODE_ES
        JNE >E6
     E5:
        PUSH AX
        MOV AL,[ES:DI-1]                ; get segment override
        EXTRN GETDIVISOR_SEGOVR:B
        MOV GETDIVISOR_SEGOVR,AL        ; store segment override
        POP AX
     E6:
        POP ES,DI
; Now everything is as it was.  The environment is identical to what it
; was when the interrupt occurred (except for the flags and of course
; CS:IP).  Only this time, the instruction is MOV SI, or MOV DH, instead
; of a DIV.
GETDIVISOR_SEGOVR DB
        NOP             ; placeholder for segment override
GETDIVISOR DB
        NOP             ; placeholder for the MOV instruction
        NOP             ; placeholder for the EA byte
GETDIVISOR_WOFS DW
        NOP             ; placeholders for any offsets
        NOP
;
        MOV AX,SI                       ; get word divisor...
        CMP GETDIVISOR,OPCODE_MOV_B     ; ...unless it's a byte...
        JNE >F1
        MOV AL,DH                       ; ...in which case, get byte divisor
        JMP >F2
     F1:
        PUSH AX
        MOV AL,AH
        LEA BX,DIVISORHEX
        CALL >F90               ; store high byte of divisor
        POP AX
     F2:
        LEA BX,DIVISORHEX[2]
; store low byte of divisor
;
F90:            ; store AL as 2 hex digits
        PUSH AX
        ROR AL,1
        ROR AL,1
        ROR AL,1
        ROR AL,1
        CALL LNALTOHEX
        MOV DIVISORHEX[2],DL
        POP AX
        CALL LNALTOHEX
        MOV DIVISORHEX[3],DL
        RET
PRINTAXASHEX:           ; print out AX in hex
        MOV CX,4
     P1:
        ROL AX,1
        ROL AX,1
        ROL AX,1
        ROL AX,1
        CALL LNALTOHEX
        PUSH AX
        MOV AH,6
        INT 021
        POP AX
        LOOP P1
        RET
LNALTOHEX:         ; return low nibble of AL as hex digit in DL
        MOV DL,AL
        AND DL,0F
        ADD DL,'0'
        CMP DL,'9'
        IF A ADD DL,'@'-'9'
        RET
CW_LOC  DW ?
CW_RM   DW ?
CHECKWALL:
        MOV SI,LASTGOOD_AD
    CW0:
        PUSH LASTGOOD_RM
        POP CW_RM
    CW1:
        PUSH AX
        CMP SI,160*24
        IF AE CALL CW_OTHERRM
        MOV CW_LOC,SI
        PUSH BX
        PUSH CX
        PUSH DX
        MOV AX,SI
        DIV v_160
        CMP ROOM,0
        IF E JMP RM0
        TEST LC_FLAG,0E0
        JZ >L4
        MOV CX,AX
        TEST LC_FLAG,020   ;castle?
        JNZ >L3            ;yes
;                      ; if not, must be Line room
        MOV AX,[OBJECT+OSZ*14]       ;dot (original dot)
        TEST LC_FLAG,080               ; if Left Line,
        IF NZ MOV AX,[OBJECT+OSZ*15]   ; then check for Left-Dot
        CMP AX,CW_RM
        JNE >A1
        CALL BLINK_UNBLOCK
        JZ >L3
     A1:
        MOV BH,LINE_MARGIN
        TEST LC_FLAG,040
        IF NZ MOV BH,158-LINE_MARGIN
        AND BH,0FC   ;exact multiple of 4
        CMP CH,BH
        JNE NOSPRM
     L2:
        MOV AL,0
        DEC AL     ;NZ
        STC        ; C = "special" (not a wall)
        LAHF
        PUSH AX
        CALL CW_WALLBIT
        POP AX
        IF NZ AND AH,0FE   ;if both wall and Special, then C flag = "wall"
        SAHF
        JMP CW1A
     L3:
        CALL BLINK_UNBLOCK
        JZ NOSPRM
        TEST LC_FLAG,010   ;gate open?   (1=open)
        JNZ NOSPRM
        CMP CCLOSE_CNT,0
        JNE NOSPRM  ; if gate is closing, may still go through it
        CMP SI,160*14
        JB NOSPRM
        CMP CH,76
        JB NOSPRM
        CMP CH,82
        JA NOSPRM
        CMP SI,160*18
        JB L2
     L4:
        CALL BLINK_UNBLOCK
        JZ NOSPRM
        TEST LC_FLAG,8  ; 'created by' message?
        JZ NOSPRM
        CMP AH,76
        JB NOSPRM
        CMP AH,82
        JA NOSPRM
        CMP CW_LOC,160
        JAE L2
        PUSH AX
        MOV AX,JUP
        CMP VMOV,AX
        POP AX
        JA L2
        JMP NOSPRM
NOSPRM:  ;  That's "NO SPecial RooMs" --- NOT "no sperm"!
        CALL CW_WALLBIT
        CLC     ;NC p wall (not line, or gate, or message)
   CW1A:
        POP DX
        POP CX
        POP BX
        POP AX
        RET
EXTRN   GAMENO_STR:NEAR
RM0:
        CMP SI,160*10+76
        JB NOSPRM
        CMP SI,160*11+82
        JA NOSPRM
        CMP AH,76
        JB NOSPRM
        CMP AH,82
        JA NOSPRM
        SUB AL,10
        IF NZ MOV AL,3
        SUB AH,78
        IF S MOV AH,0
        SHR AH,1
        ADD AL,AH
        CBW
        MOV BX,AX
        MOV AL,GAMENO
        DEC AL
        MOV AH,6
        MUL AH
        ADD BX,AX
        ADD BX,VGA
        CMP B[GAMENO_STR][BX],' '
        JE NOSPRM
        JMP L2
CHECKACTUAL:
        MOV SI,PL_AD
CHECKWALL_SI:
        PUSH AX
        MOV AX,ROOM
        MOV CW_RM,AX
        POP AX
        JMP CW1
CW_OTHERRM:
        CMP SI,160*26    ;room below?
        JB CW3
        ADD SI,160*24
        MOV AX,[BX+4]
        JMP SHORT CW4
    CW3:
        SUB SI,160*24
        MOV AX,[BX+6]
    CW4:
        MOV CW_RM,AX
        RET
CW_WALLBIT:   ;Entry: CW_RM, CW_LOC       Exit: SI=byte, AL=bit mask
        PUSH SI
        MOV SI,ROOMDAT
        MOV CX,320
        CMP CW_RM,-1
        JE CWB3
        CMP CW_RM,331
        JE CWB2
   CWB0:
        MOV AX,CW_RM
        MOV BX,60
        MUL BX
        ADD SI,AX
   CWB1:MOV AX,CW_LOC
        MOV DX,0
        DIV CX
        MOV AH,5
        MUL AH
        ADD SI,AX
        MOV AX,CW_LOC
        DIV v_160
        SHR AH,1
        MOV CH,AH
        AND CH,0F
        MOV AL,AH
        MOV CL,4
        SHR AL,CL
        MOV AH,0
        ADD SI,AX
        SHR CH,1
        MOV CL,CH
        MOV AL,080
        SHR AL,CL
        TEST [SI],AL
        POP SI
        RET
   CWB2:
        SHR CX,1
        JMP CWB0
   CWB3:
        MOV SI,TITLE_ROOMDAT
        SHR CX,1
        JMP CWB1
BLOCKED_H:
        CMP SWALLOWED,0
        JNE >B2          ; Player, if swallowed, can't go ANYWHERE
        CALL BLINK_UNBLOCK
        JZ >B1
        CALL CHECKALLDRAGONS
        JNZ >B2
     B1:
        CALL CHECKACTUAL   ; hit wall, message, closed gate, line?
        JNZ >B2
        CALL CHECKWALL     ; already in a wall, etc?
        JNZ >B2
        CALL PL_TOUCHING_OBJ?
        JNZ >B3
     B2:
        CLC
        RET
     B3:
        STC
        RET
BITE:
;        CMP SWALLOWED,SI
        CMP DR_STATUS,HAS_EATEN
        JE RET
;        MOV B TD_ROWCNT,2  ; must touch "front" (left side) of dragon
     B1:
        MOV AL,DR_STATUS
        DEC AL
        CMP AL,BITING-1
        JGE RET
        MOV AX,ROOM
        CMP AX,[SI]
        JNE RET
;        PUSH LOC
;        AND B[SI+3],07F
;        MOV AX,LASTGOOD_AD
;        SUB AX,LOC
;        POP LOC
;        JE BITEM
;        MOV BL,HMOV
;        SUB BL,JLEFT
;        JBE >B2
;        CMP BL,JRIGHT-JLEFT
;        JB >B3
;     B2:  ; player moving horizontally
;        CMP AX,4
;        JB BITEM
;     B3:
;        MOV BL,VMOV
;        SUB BL,JUP
;        JBE >B4
;        CMP BL,JDOWN-JUP
;        JB RET
;     B4:
;        CMP AX,160
;        JE BITEM
        MOV AX,PL_AD
        MOV TD_LOC,AX
        CALL TOUCHING_DRAGON?
        JNZ >B3
        ADD TD_LOC,2
        CALL TOUCHING_DRAGON?
        JNZ >B3
        MOV AX,LASTGOOD_AD
        MOV TD_LOC,AX
        CALL TOUCHING_DRAGON?
        JNZ >B3
        ADD TD_LOC,2
        CALL TOUCHING_DRAGON?
        JNZ >B3
        RET
     B3:
        PUSH LASTGOOD_AD  ;PL_AD
        POP LOC
  BITEM:
        CMP GAMENO,1
        JE >B5
        MOV AL,BITING+8
        CMP LDIF,0
        IF E ADD AL,5
     B4:
        MOV DR_STATUS,AL
        MOV SOUND_PTR,SOUND_BITE
        MOV SOUND_START,-1
        RET
     B5:
        MOV AL,BITING+20
        CMP LDIF,0
        IF E ADD AL,20
        JMP SHORT B4
BLOCKED_V:     ; input: AX = 0A0 or -0A0  (down or up)
        CMP SWALLOWED,0
        JNE >X4   ; Player, if swallowed, can't go ANYWHERE
        CALL BLINK_UNBLOCK
        JZ >B1
        MOV SI,LASTGOOD_AD
        ADD SI,AX
        CALL BETWEEN_BRIDGE?
        JZ >X5
        CALL CHECKALLDRAGONS
        JNZ >X4
        PUSH AX
        MOV AX,JUP
        CMP VMOV,AX      ; if moving up...
        POP AX
        JBE >X0          ; then do.
        PUSH AX
        MOV AX,JLEFT
        CMP HMOV,AX       ; if not moving up, but moving left...
        POP AX
        JNA >B1           ; then skip.
     X0:
        PUSH AX,BX           ;  Otherwise, can't move out of dragon's bite.
        MOV SI,DRAGON
        MOV AX,LASTGOOD_RM
        MOV BX,LASTGOOD_AD
     X1:
        CMP AX,[SI]
        JNE >X2
        CMP BX,LOC
        JE >X3
     X2:
        ADD SI,DRSZ
        CMP SI,DRAGON+DRSZ*3
        JBE X1
        POP BX,AX
        JMP >B1
     X3:
        OR AL,1   ; set NZ
        POP BX,AX
     X4:
        CLC
        RET
     B1:
        MOV SI,LASTGOOD_AD
        ADD SI,AX
        CALL CW0    ; hit wall, message, closed gate, line?
        JNZ X4
        CALL BETWEEN_BR_LG  ; Lastgood between bridge?
        JZ >X5              ; if so skip
        PUSH AX
        MOV AX,ROOM
        CMP AX,LASTGOOD_RM
        POP AX
        JNE >B2
        MOV SI,LASTGOOD_AD
        CALL CW0    ; already in a wall, message, etc?
        JNZ X4
     X5:
        PUSH AX
        CALL PL_TOUCHING_OBJ?
        POP AX
        JNZ >X6
     B2:
        CMP AL,AL
        RET
     X6:
        STC
        RET
BLINK_UNBLOCK:
        CMP BLINK_CTR,3
        JB RET
        TEST LCNT,1
        RET
PL_TOUCHING_OBJ?:   ; NZ = "yes"
        PUSH PL_AD
        POP COBJ_LOC
        MOV SI,OBJECT
     P1:
        CALL CONTACT_OBJ?
        JZ >P3
        ADD SI,OSZ
        CMP SI,DRAGON
        JA >P2
        JB P1
        MOV SI,BAT
        JMP P1
     P2:
        XOR AL,AL
        RET
     P3:
        MOV TOUCHED_OBJ,SI   ;record what we've collided with
        OR AL,1
        RET
CHECKALLDRAGONS:
        MOV B TD_ROWCNT,4
        PUSH SI
        MOV SI,DRAGON
     C1:
        CMP SWALLOWED,SI  ;automatically blocked
        JE >L1
        PUSH AX
        MOV AL,DR_STATUS
        DEC AL
        CMP AL,BITING-1 ; neither biting nor dead?
        POP AX
        JL >C2   ; if alive (and not biting), skip
     L1:
        PUSH PL_AD
        POP TD_LOC
        CALL TOUCHING_DRAGON?
        JNZ >C3
        ADD TD_LOC,2
        CALL TOUCHING_DRAGON?
        JNZ >C3
;        CMP DR_STATUS,BITING
;        JGE >C2
;        PUSH LASTGOOD_AD
;        POP TD_LOC
;        CALL TOUCHING_DRAGON?
;        JNZ >C3
;        ADD TD_LOC,2
;        CALL TOUCHING_DRAGON?
;        JNZ >C3
     C2:
        ADD SI,DRSZ
        CMP SI,DRAGON+DRSZ*4
        JB C1
        CMP AL,AL
     C3:
        POP SI
        RET
TD_LOC  DW ?
TD_ROWCNT DB 4
TOUCHING_DRAGON?:    ; entry:  SI = addr of Dragon data
        PUSH AX,BX,CX,DX,DI
     TD1:
        MOV AX,ROOM
        CMP AX,[SI]
        IF NE JMP TD4
        MOV CX,5
        MOV BX,DRAGON_STR1
        MOV DI,LOC
        TEST DI,08000
        IF NZ MOV BX,DRAGON_STR2
        ADD BX,VGA
        CMP BX,VGA_DRAGON_STR2
        IF E INC CX
        CMP DR_STATUS,BITING
        JNGE >L1
        MOV BX,DRAGON_BITE
        INC CX
     L1:
        CMP DR_STATUS,DEAD
        IF E MOV BX,DRAGON_CORPSE
        AND DI,07FFF        ; get dragon's screen loc
        MOV AX,DI
        DIV v_160           ; AL = row, AH = col
        MOV DH,AH           ; save col
    TD2:
        MOV AH,TD_ROWCNT    ; counter
        MOV DL,158          ; DL = as far right as we're willing to check
        PUSH BX
        PUSH DI
    TD3:
        CMP DI,TD_LOC       ; dragon right on this loc?
        JNE >L0             ; no
        CMP B[BX],020       ; yes, but is there any "dragon" (gr. bits) there?
        JE >L0              ; no, so go on to next loc
        POP DI              ; yes, so we're touching dragon
        POP BX
        JMP >L2             ; exit with NZ condition still present
     L0:
        CMP DH,DL           ; checked all the way to right edge of screen?
        JAE >L1             ; yes, so we're done with this row
        SUB DL,2            ; otherwise move us closer to right edge
        ADD DI,2            ; increment dragon's screen loc (to the right)
        INC BX              ; increment pointer to graphic data
        DEC AH              ; dec counter
        JNZ TD3
     L1:
        POP DI
        ADD DI,160          ; increment row
        POP BX
        ADD BX,4            ; increment row of pointer to graphics data
        CMP DI,160*24       ; off the screen?
        JAE TD4             ; yes, so we're done
        LOOP TD2
    TD4:
        CMP AL,AL           ; no touching found, so set Z = not touching
     L2:
        POP DI,DX,CX,BX,AX  ; else NZ = touching
        RET
DECBITE:
        DEC DR_STATUS
        CMP DR_STATUS,BITING
        JGE RET
        MOV HINC,2
        MOV AX,ROOM
        CMP AX,RM
        JNE RET
        MOV AX,LOC
        AND AH,07F
        SUB AX,LASTGOOD_AD  ;PL_AD
        NEG AX
        ADD AX,2    ;
        CMP AX,6+2  ; i.e. from -2 to 6
        JBE DECB1
;        MOV AX,PL_AD
;        SUB AX,TEMP
;        CMP AX,324
;        JE DECB1
;;
;        MOV AX,PL_AD
;        MOV TD_LOC,AX
;        CALL TOUCHING_DRAGON?
;        JNZ DECB1
;        ADD TD_LOC,2
;        CALL TOUCHING_DRAGON?
;        JNZ DECB1
        RET
   DECB1:
;        MOV AX,PL_AD
;        SUB AX,LASTGOOD_AD
;        CMP AX,160-4          ; if player is moving down but is blocked,
;        JB >X1
;        CMP AX,160+4
;        JBE RET               ; then can't be swallowed
;     X1:
        PUSH SI
        CALL CHECKACTUAL      ; if moving against a wall...
        POP SI
        JZ >X2
        PUSH AX
        MOV AX,JDOWN
        CMP VMOV,AX           ; ... and if moving down, then can't be swallowed
        POP AX
        JAE RET
     X2:
        MOV DR_STATUS,HAS_EATEN
; erase player
        MOV AH,CAT
        CMP ROOMCOLOR,AH
        IF E MOV AH,040
        PUSH SI
        CALL CHECKWALL
        POP SI
        IF NZ MOV AH,ROOMCOLOR
        PUSH DI
        MOV ES,VIDSEG_MAIN
        MOV DI,LASTGOOD_AD
        MOV AL,[ES:DI+1]
        AND AL,0F
        OR AL,AH
        MOV [ES:DI+1],AL
        MOV AL,[ES:DI+3]
        AND AL,0F
        OR AL,AH
        MOV [ES:DI+3],AL
        POP DI
;
        CMP SWALLOWED,0     ; already been swallowed?
        JNE >D3             ; yes, so don't move player around anymore
        MOV SWALLOWED,SI
        MOV AX,LOC
        TEST AH,080
        IF NZ SUB AX,08000-160
        ADD AX,322
        CMP AX,160*24
        JB >D2
        SUB AX,160*24
        PUSH AX,BX,SI,ES
        MOV BX,ROOM
        CALL GETMAPADDR
        MOV AX,[BX+6]  ;room below
        MOV LASTGOOD_RM,AX
        CALL PUTROOM
        POP ES,SI,BX,AX
     D2:
        MOV LASTGOOD_AD,AX
        MOV PL_AD,AX
     D3:
        MOV SOUND_PTR,SOUND_SWALLOW
        MOV SOUND_START,-1
        RET
KILLDRAGON:
;        CMP SWALLOWED,SI
        CMP DR_STATUS,HAS_EATEN
        JE RET
        MOV AX,ROOM
        CMP AX,[OBJECT] ;sword present?
        JNE RET
        MOV AL,DR_STATUS
        DEC AL
        CMP AL,BITING-1
        JGE RET
        MOV CX,2
        MOV AX,[OBJECT+2]
     L0:
        PUSH CX
        MOV CX,4
        MOV TD_ROWCNT,CL
     L1:
        MOV TD_LOC,AX
        CALL TOUCHING_DRAGON?
        JNZ >L2
        ADD AX,2
        LOOP L1
        POP CX
        ADD AX,160-4*2
        LOOP L0
        RET
     L2:
        POP CX
        MOV DR_STATUS,DEAD
        AND B[SI+3],07F
        MOV SOUND_PTR,SOUND_STAB
        MOV SOUND_START,-1
        RET
JOYSTICK_NOT_FOUND:
;        MOV HMOV,32
;        MOV VMOV,32
        STI
        DMOV JOYVALS,START_JOYVALS
        STC
        RET
JOYSTICK:
        CMP BIOSJOYSTICK,0
        IF NE JMP READBIOSJOYSTICK
        MOV DX,0201
        MOV AL,0FF
        OUT DX,AL
        IN AL,DX
        MOV BUTTONS,AL
        MOV AL,0FF
#IF 1
        EXTRN HIRESTIMER:W
        MOV BP,HIRESTIMER
        MOV AL,0FF
        OUT DX,AL
     L2:                        ; read X coordinate
        MOV AH,AL
        IN AL,DX
        AND AL,3
        MOV BX,HIRESTIMER
        SUB BX,BP
        CMP BX,v_JOYSTICK_TIMEOUT            ; timed out?
        JAE JOYSTICK_NOT_FOUND
        PUSH AX
        AND AX,0101
        XOR AL,AH
        IF NZ MOV HMOV,BX
        POP AX
        PUSH AX
        AND AX,0202
        XOR AL,AH
        IF NZ MOV VMOV,BX
        POP AX
        TEST AL,3
        JNZ L2
     L5:
#ELSE
        MOV CL,3  ;CL: flag--XXXXXXX0 = X done, XXXXXX0X = Y done
        XOR BX,BX       ; BX = X value
        XOR BP,BP       ; BP = Y value
        MOV DI,01000             ; max-out value
        CLI
        OUT DX,AL
     L2:
        IN AL,DX
        TEST CL,1     ;X coordinate already found?
        JZ >L4
        TEST AL,1
        JZ >L3
        INC BX
        JMP >L4
     L3:
        AND CL,0FE   ;X done
     L4:
        TEST CL,2    ;Y coordinate already found?
        JZ >L6
        TEST AL,2
        JZ >L5
        INC BP
        JMP >L6
     L5:
        AND CL,0FD   ;Y done
     L6:
        DEC DI
        JZ JOYSTICK_NOT_FOUND    ; timed out
        CMP BX,TEMP
        JAE JOYSTICK_NOT_FOUND
        CMP BP,TEMP[2]
        JAE JOYSTICK_NOT_FOUND
        TEST CL,3
        JNZ L2
     L7:
        STI
        MOV HMOV,BX
        MOV VMOV,BP
#ENDIF
        CLC
        RET
     N0:JMP JOYSTICK_NOT_FOUND
READBIOSJOYSTICK:
        MOV AH,084
        XOR DX,DX
        INT 015
        JC N0
        MOV BUTTONS,AL
        MOV AH,084
        MOV DX,1
        INT 015
        JC N0
        MOV HMOV,AX
        MOV VMOV,BX
        CLC
        RET
ATARIJOYSTICK:          ; uses MULTIJOY setup
        MOV DX,MULTIPORT
        CMP DX,-1
        IF E JMP JOYSTICK_NOT_FOUND
        DMOV JOYVALS,START_JOYVALS      ; start with "neutral" values
        MOV BUTTONS,0FF
        XOR BX,BX
        CALL AJ_TESTBIT         ; moving left?
        JZ >A1
        MOV HMOV,0              ; set left movement
        JMP >A2
     A1:
        INC BX
        CALL AJ_TESTBIT         ; moving right?
        IF NZ SHL HMOV,1        ; set right movement
     A2:
        MOV BX,2
        CALL AJ_TESTBIT         ; moving up?
        JZ >A3
        MOV VMOV,0              ; set upward movement
        JMP >A4
     A3:
        INC BX
        CALL AJ_TESTBIT         ; moving down?
        IF NZ SHL VMOV,1        ; set downward movement
     A4:
        MOV BX,4
        CALL AJ_TESTBIT         ; button pressed?
        IF NZ AND BUTTONS,0EF
        RET
AJ_TESTBIT:                     ; returns ZF=1 if joystick switch not clicked
        MOV AL,AJ_INDEX[BX]
        OUT DX,AL
        MOV CX,32                       ; arbitrary value
     Z1:
        NOP
        LOOP Z1
        INC DX
        IN AL,DX
        DEC DX
        CMP AJ_BIT[BX],080
        IF E NOT AL
        AND AL,AJ_BIT[BX]
        RET
NEW_CHR_COLOR:
        AND AH,0F0
        OR AH,DL
        RET
LOADALL:  ; Entry: AL=Index (game number) (0 is beginner)
#IF REGISTERED
        PUSH AX
#ENDIF
        MOV SI,STARTDATA
        MOV AH,OSZ*(16+4+1)  ;for each object, dragon or bat: a room & address
        MUL AH
        ADD SI,AX
        MOV ES,DS
        MOV DI,OBJECT
        MOV CX,16
     L0:
#IF REGISTERED
        LODSW
        CMP AX,v_RDIST_REG
        JNLE >R1
        MOV DX,AX
     R0:
        MOV AX,DX
        PUSH DX
        CALL GETRANDOMROOM
        CALL ROOMEMPTY?    ; place each object in a room by itself
        POP DX
        JNZ R0
     R1:
        STOSW
#ELSE
        MOVSW
#ENDIF
        MOVSW
        LOOP L0
#IF REGISTERED
        CMP GAMENO,5
        IF E CALL GAME5_STUFF
        CALL CHECKFORKEYLOOPS
        POP AX
        JZ LOADALL  ; found infinite loop in key locations;  do again
#ENDIF
        MOV DI,DRAGON
        MOV CX,5  ;4 dragons & bat
     L1:
#IF REGISTERED
        LODSW
        CMP AX,v_RDIST_REG
        IF LE CALL GETRANDOMROOM
        STOSW
#ELSE
        MOVSW
#ENDIF
        MOVSW
        MOV AX,0
        STOSW
        LOOP L1
#IF REGISTERED
        CMP GAMENO,3
        IF AE MOV W[BAT+4],1 BY 1  ; V and H movement
        MOV BAT_CARRYING,-1
        MOV BAT_OBJINSIGHTS,OBJECT
#ENDIF
        RET
#IF REGISTERED
GAME5_STUFF:
        MOV DI,0
        MOV AX,v_RDIST_REG
        CALL GETRANDOMROOM
        CMP AX,30    ; avoid rooms 30 & 31
        JAE GAME5_STUFF
        MOV [OBJECT+OSZ*n_BRIDGE],AX
     S1:
        MOV AX,[OBJECT+OSZ*n_BRIDGE]
        CALL GAME5_CHECKFORLOOP
        JCXZ S1
;     S2:
        CMP W[OBJECT+OSZ*n_KEY_YELLOW],0
        JNE >S3
        MOV AX,v_RDIST_EXT
        CALL GETRANDOMROOM
        MOV W[OBJECT+OSZ*n_KEY_YELLOW],AX
     S3:
        CMP W[OBJECT+OSZ*n_KEY_WHITE],0
        JNE >S4
        MOV AX,v_RDIST_EXT
        CALL GETRANDOMROOM
        MOV W[OBJECT+OSZ*n_KEY_WHITE],AX
     S4:
        MOV AX,W[OBJECT+OSZ*n_KEY_BLACK]
        CMP AX,0
        JNE >S6
     S5:
        MOV AX,v_RDIST_REG   ; black key must be in REG area so Dot is reachable
        CALL GETRANDOMROOM
     S6:
        CALL GRR_FINDCASTLE
        CMP BL,n_KEY_BLACK      ; can't put Black Key in Black Castle
        JE S5
        MOV W[OBJECT+OSZ*n_KEY_BLACK],AX
        CALL GAME5_CHECKFORLOOP
        JCXZ S5
        RET
GAME5_CHECKFORLOOP:
        MOV CX,3   ; to prevent infinite loop
     C1:
        CALL GRR_FINDCASTLE     ; is AX a room in a castle?
        JE >C2                  ; object isn't in a castle, so we're done
        MOV AX,v_RDIST_REG      ; key for this castle must be in REG area
        PUSH BX
        CALL GETRANDOMROOM
        POP BX
        MOV DI,OBJECT
        PUSH AX
        MOV AL,OSZ              
        MUL BL                  ; BL=number of castle (1-5)
        ADD DI,AX
        POP AX
        MOV [DI],AX             ; place castle's key in a random room
        LOOP C1                 ; and check whether THAT key is accessible
     C2:
        RET
GETRANDOMROOM:
        MOV DX,AX
        CMP AX,v_RDIST_REG
        JNE GRR1
     G1:
        CALL RANDNUM
        AND AX,01F
        JZ G1
        CMP AX,5    ; can't be in secret room
        JE G1
        CMP AX,21   ; nor "lower" secret room
        JE G1
        CALL GRR_CHALICEINYC?
        JZ G1
        CMP DX,v_RDIST_REG_CASTLE
        JNE >G5
        CALL GRR_FINDCASTLE
        JZ G1
        JMP >G5
   GRR1:
        CMP AX,v_RDIST_REG_CASTLE
        JE G1
     G2:
        CALL RANDNUM
        AND AX,01FF
        JZ G2
        CMP AX,MAX_ROOMNO
        JNA >G3
        SHR AX,1
        JZ G2
     G3:
        CALL GRR_CHALICEINYC?
        JZ G2
        CMP DX,v_RDIST_EXTONLY
        JNE >G4
        CMP AX,31
        JA >G4
        CMP AX,21
        JNE G2
     G4:
        CMP DX,v_RDIST_EXT_CASTLE
        JNE >G5
        CALL GRR_FINDCASTLE
        JE G2
     G5:
        RET
GRR_CHALICEINYC?:
        CMP DI,OBJECT+OSZ*n_CHALICE
        JNE RET
        CMP AX,22
        RET
ROOMEMPTY?:
        MOV BX,OBJECT
     R1:
        CMP BX,DI
        JE RET
        CMP AX,[BX]
        PUSHF
        ADD BX,OSZ
        POPF
        JNE R1
        OR BL,1   ; force NZ
        RET
CHECKFORKEYLOOPS:
; check for infinite loop in key locations
; (e.g., yellow key in black castle and black key in yellow castle)
; Z = 0 if OK, Z = 1 if loop is found
        MOV DH,1     ; DH = Key-to-Check
CFKL0:
        MOV DL,DH
        MOV CL,0
CFKL1:
        MOV BX,OBJECT
        MOV AL,OSZ
        MUL DL
        ADD BX,AX
        MOV AX,[BX]   ; get room
        CALL GRR_FINDCASTLE  ; BX = number of castle containing room AX
        MOV DL,BL
        CMP DL,DH     ; must we get into the very castle of the Key-to-Check?
        JE RET     ; Z set means check FAILED
        INC CL
        CMP CL,10
        JA >C2    ; timed out
        CMP DL,0
        JNE CFKL1
     C2:
        INC DH
        CMP DH,5
        JBE CFKL0
        RET      ; Z = 0 means A-OK
GRR_FINDCASTLE:   ; expects AX = room
; returns BX = 1 (yellow castle) - 5 (flashing castle)
; also returns Z=1 if no castle
        MOV BX,20
GRRF1:
        SUB BX,4
        CMP AX,CASTLE_ROOMS_RANGE[BX]
        JB >X0
        CMP AX,CASTLE_ROOMS_RANGE[BX+2]
        JA >X0
        SHR BX,1
        SHR BX,1
        INC BX
        RET
     X0:
        CMP BX,0
        JG GRRF1
        RET
#ENDIF
;FILLSCN_SPACES:
;        MOV SI,OBJECT
;     L0:
;        CALL ERASE_OBJ
;        ADD SI,OSZ
;        CMP SI,DRAGON
;        JB L0
;        JMP PUTGATE
;        RET
ERASE_OBJ:    ; Entry:  SI=address somewhere in OBJECT
        MOV AX,ROOM
        CMP AX,[SI]
        JNE RET
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,LOC
        AND DI,07FFF
        CMP DI,160*24
        JAE RET
        CALL SIZEOFOBJ
        MOV CX,[BX]
        CMP CL,16  ;bridge?
        JE >L4
;        CMP ROOMCOLOR,CAT
;        JNE RET
        MOV TEMPB,CL
     L1:
        MOV CL,TEMPB
        MOV AX,DI
        DIV v_160
        MOV DH,AH
        MOV AL,020
        PUSH DI
     L2:
        MOV [ES:DI],AL
        ADD DI,2
        ADD DH,2
        CMP DH,160
        JAE >L3
        DEC CL
        JNZ L2
     L3:
        POP DI
        ADD DI,160
        CMP DI,160*24
        JAE >E1
        DEC CH
        JNZ L1
;
     E1:
     E2:RET
     L4:
     L5:
        PUSH DI
        MOV AX,DI
        DIV v_160
        MOV DH,AH
        MOV AL,020
        CMP CH,6
        JE >L6
        CMP CH,1
        JNE >L7
     L6:
        MOV [ES:DI],AL
        CMP DH,158
        JAE >L9
        MOV [ES:DI+2],AL
        CMP DH,156
        JAE >L9
     L7:
        ADD DI,4
        ADD DH,4
        MOV [ES:DI],AL
        ADD DH,2
        CMP DH,160
        JAE >L9
        MOV [ES:DI+2],AL
        ADD DH,2+16
        CMP DH,160
        JAE >L9
        MOV [ES:DI+20],AL
        ADD DH,2
        CMP DH,160
        JAE >L9
        MOV [ES:DI+22],AL
        CMP CH,6
        JE >L8
        CMP CH,1
        JNE >L9
     L8:
        ADD DH,2
        CMP DH,160
        JAE >L9
        MOV [ES:DI+24],AL
        ADD DH,2
        CMP DH,160
        JAE >L9
        MOV [ES:DI+26],AL
     L9:
        POP DI
        ADD DI,160
        CMP DI,160*24
        JAE RET
        DEC CH
        IF NZ JMP L5
        RET
PUTOBJ_CHAR:
        CMP ROOMCOLOR,CAT
        JNE >P1
        CALL CHECKWALL_SI
        JNZ RET
     P1:
        MOV AH,[ES:SI+1]
        CALL NEW_CHR_COLOR
        MOV [ES:SI],AX
        RET
PICKUP_BUMPOBJ:   ; entry: SI=address in OBJECT
        PUSH AX
        MOV AX,JLEFT
        CMP HMOV,AX
        POP AX
        JA >K1
        SUB LOC,4
        JMP >K2
     K1:
        PUSH AX
        MOV AX,JRIGHT
        CMP HMOV,AX
        POP AX
        JB >K2
        ADD LOC,4
     K2:
        MOV BX,[SI]
        CALL GETMAPADDR
        MOV DI,BX
        PUSH AX
        MOV AX,JUP
        CMP VMOV,AX
        POP AX
        JA >K3
        SUB LOC,0A0
        JNS >K4
        MOV AX,LOC
        ADD LOC,160*24
        MOV BX,[DI+4]
        MOV [SI],BX
        JMP >K5
     K3:
        PUSH AX
        MOV AX,JDOWN
        CMP VMOV,AX
        POP AX
        JB >K4
        ADD LOC,0A0
        CMP LOC,160*24
        JB >K4
        PUSH LOC
        CALL OBJ_OFFBOTTOM
        POP AX
        JMP >K5
     K4:
        MOV AX,LOC
     K5:
        RET
COBJ_LOC DW 0
DR_DIM:  DB 4,5
         DB 4,6
BAT_DIM: DB 4,3
CONTACT_OBJ?:  ; Entry: SI=addr in OBJECT,  COBJ_LOC = place to check
;                Exit:  Z flag set = yes (touching)
        MOV AX,ROOM
        CMP AX,[SI]
        JNE NOCONTACT
;        CMP SI,CARRYING
;        JE NOCONTACT    ; can't pick up something you already have
        CMP SI,BAT
        JNE >L0
        MOV DI,BAT_DIM
        JMP >C1
     L0:
        PUSH BX
        CALL SIZEOFOBJ
        MOV DI,BX
        POP BX
     C1:
        MOV AX,LOC
        SUB AX,2
        MOV CL,[DI+1]  ;vertical dimension
        MOV CH,0
     L1:
        PUSH CX
        PUSH AX
        MOV CL,[DI]    ;horizontal dimension
        MOV CH,0
        INC CX
     L2:
        CMP AX,COBJ_LOC
        JNE >L3
        CMP SI,OBJECT+OSZ*7  ;bridge?
        JNE >K0              ; if not, then must be touching
        CMP CL,5             ;  in the middle?
        JB >J1               ;
        CMP CL,12            ;
        JBE >L3              ;
     J1:
        MOV BP,SP     ;
        CMP B[BP+2],6 ; top of bridge?
        JE >K0        ;
        CMP B[BP+2],1 ; bottom of bridge?
        JE >K0        ;
        CMP CL,15  ; left edge?
        JA >L3     ;
        CMP CL,3   ; right edge?
        JB >L3     ;
     K0:
        ADD SP,4
        MOV AL,1
        JMP >L4
     L3:
        ADD AX,2
        LOOP L2
        POP AX
        POP CX
        ADD AX,160
        LOOP L1
NOCONTACT:
        MOV AL,0
     L4:
        DEC AL
        RET
PICKED_UP_BAT:
        PUSH BX
        MOV BX,BAT_CARRYING
        CMP BX,SWALLOWED
        JNE >P1
        MOV AX,BAT_CD
        ADD AX,322
        TEST B[BX+3],080
        IF NZ ADD AX,160
        NEG AX
     P1:
        POP BX
        RET
CALC_LASTGOOD:
;  Calculate LASTGOOD_AD value from current movement, and return in DX
;
        PUSH AX
        MOV AX,HMOV
        MOV DX,PL_AD
        CMP AX,JLEFT
        IF BE ADD DX,4
        CMP AX,JRIGHT
        IF AE SUB DX,4
        MOV AX,VMOV
        CMP AX,JUP
        IF BE ADD DX,160
        CMP AX,JDOWN
        IF AE SUB DX,160
        POP AX
        RET
AD_INT8 DD
ORIGINAL_INT8 DW 0,0
HIRESTIMER DW 0
TIMERCOUNT DW 0
TIMERINT:
        CLI
        INC CS:HIRESTIMER
        ADD CS:TIMERCOUNT,v_TIMERLOOPSIZE
        JC >T1
        STI
        PUSH AX
        MOV AL,020
        OUT 020,AL                              ; EOI
        POP AX
        IRET
     T1:
        JMP D[CS:AD_INT8]
